﻿using System.Collections.Generic;
using HHPS.CreditEducation.DataProvider;
using HHPS.CreditEducation.Frameworks.Constants;
using Enumerable = System.Linq.Enumerable;
using Queryable = System.Linq.Queryable;

namespace HHPS.CreditEducation.Business
{
    public class UniversityBusiness
    {
        private readonly CreditEducationDbEntities _dataContex;

        public UniversityBusiness()
        {
            _dataContex = new CreditEducationDbEntities();
        }

        #region -- Faculty --

        /// <summary>
        /// This function shows list of faculties.
        /// </summary>
        /// <returns></returns>
        public List<Faculty> GetListFacutly()
        {
            return _dataContex != null ? Enumerable.ToList(_dataContex.Faculties) : null;
        }

        /// <summary>
        /// This function check validate of add a new facutly function
        ///     Is name exist?
        /// </summary>
        /// <param name="nameFacutly"> Name of facutly </param>
        /// <returns></returns>
        public string AddFacultyValidator(string nameFacutly)
        {
            if (string.IsNullOrEmpty(nameFacutly))
                return string.Format(ConstantMessages.RequireFieldIsBlank, "tên khoa");

            if (nameFacutly.Length >= 50)
                return string.Format(ConstantMessages.FieldDataOverMaxLength, nameFacutly, 50);

            return Queryable.Any(_dataContex.Faculties, f => f.Name.ToLower() == nameFacutly.ToLower())
                       ? string.Format(ConstantMessages.ItemIsExisted, nameFacutly)
                       : string.Empty;
        }

        /// <summary>
        /// This function add a new fuctly into list.
        /// </summary>
        /// <param name="nameFacutly"> Name of new facutly </param>
        public void AddFaculty(string nameFacutly)
        {
            _dataContex.Faculties.AddObject(new Faculty {Name = nameFacutly});

            _dataContex.SaveChanges();
        }

        #endregion

        #region -- Edit Faculty --

        /// <summary>
        /// This function check validate of edit a facutly function
        ///     Can defind ?
        ///     Is new name same as orther name ?
        /// </summary>
        /// <param name="idFaculty"> Id of facutly what is edited </param>
        /// <param name="nameFacutly"> New name of facutly </param>
        /// <returns></returns>
        public string EditFacultyValidator(int idFaculty, string nameFacutly)
        {
            if (!Queryable.Any(_dataContex.Faculties, f => f.Id == idFaculty))
                return ConstantMessages.CanNotIdentifyItem;

            if (string.IsNullOrEmpty(nameFacutly))
                return string.Format(ConstantMessages.RequireFieldIsBlank, "tên khoa");

            if (nameFacutly.Length >= 50)
                return string.Format(ConstantMessages.FieldDataOverMaxLength, nameFacutly, 50);

            return Queryable.Any(_dataContex.Faculties,
                                 f => f.Name.ToLower() == nameFacutly.ToLower() && f.Id != idFaculty)
                       ? string.Format(ConstantMessages.ItemIsExisted, nameFacutly)
                       : string.Empty;
        }

        /// <summary>
        /// This function edits a facutly
        /// </summary>
        /// <param name="idFaculty"> Id of facutly what is edited </param>
        /// <param name="nameFaculty"> new name of facutly what is edited </param>
        public void EditFaculty(int idFaculty, string nameFaculty)
        {
            Faculty faculty = Queryable.FirstOrDefault(Queryable.Where(_dataContex.Faculties, f => f.Id == idFaculty));

            if (faculty == null) return;

            faculty.Name = nameFaculty;

            _dataContex.SaveChanges();
        }

        #endregion

        #region -- Delete Faculty -- 

        /// <summary>
        /// This function check validate of delete list of facutlies function
        /// </summary>
        /// <param name="ids"> Id of faculty </param>
        /// <returns></returns>
        public string DeleteFacultiesValidator(int[] ids)
        {
            System.Linq.IQueryable<Faculty> selectFaculties = Queryable.Where(_dataContex.Faculties,
                                                                              f => Enumerable.Contains(ids, f.Id));

            if (_dataContex == null || Enumerable.ToList(selectFaculties).Count != ids.Length)
                return string.Format(ConstantMessages.CanNotIdentifyItem);

            System.Linq.IQueryable<int> majorsForiegnKey = Queryable.Select(_dataContex.Majors, m => m.IdFaculty);
            List<Faculty> impactedFaculties =
                Enumerable.ToList(Queryable.Where(selectFaculties, f => Queryable.Contains(majorsForiegnKey, f.Id)));
            string listNameFaculty = null;

            listNameFaculty = Enumerable.Aggregate(impactedFaculties, listNameFaculty,
                                                   (current, impactedFaculty) => current + impactedFaculty.Name + ", ");

            return listNameFaculty != null
                       ? string.Format(ConstantMessages.CannotDeleteItemInUse, listNameFaculty.TrimEnd(',', ' '),
                                       " một số ngành")
                       : string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ids"></param>
        public void DeleteFaculties(int[] ids)
        {
            System.Linq.IQueryable<Faculty> selectFaculties = Queryable.Where(_dataContex.Faculties,
                                                                              f => Enumerable.Contains(ids, f.Id));

            foreach (Faculty selectFaculty in selectFaculties)
                _dataContex.DeleteObject(selectFaculty);

            _dataContex.SaveChanges();
        }

        #endregion

        #region -- Major --

        /// <summary>
        ///  This function shows list of majors in facutly.
        /// </summary>
        /// <param name="idFaculty"> Id of facutly</param>
        /// <returns></returns>
        public List<Major> GetListMajorByFaculty(int idFaculty)
        {
            return idFaculty > 0
                       ? Enumerable.ToList(Queryable.Where(_dataContex.Majors, m => m.IdFaculty == idFaculty))
                       : Enumerable.ToList(_dataContex.Majors);
        }

        public int[] GetListIdMajorsByFaculty(int[] listIdFacultys)
        {
            return
                Enumerable.ToArray(
                    Queryable.Select(
                        Queryable.Where(_dataContex.Majors,
                                        m => Enumerable.Contains(listIdFacultys, m.IdFaculty)),
                        m => m.Id));
        }

        /// <summary>
        /// This function checks validate of add a new major into a faculty
        ///     Is Facutly exsit?
        ///     Is new name major same as orther major
        /// </summary>
        /// <param name="nameMajor"> Name of new major</param>
        /// <param name="idFaculty"> Name of faculty</param>
        /// <returns></returns>
        public string AddMajorValidator(string nameMajor, int idFaculty)
        {
            if (string.IsNullOrEmpty(nameMajor))
                return string.Format(ConstantMessages.RequireFieldIsBlank, "tên ngành");

            if (nameMajor.Length >= 50)
                return string.Format(ConstantMessages.FieldDataOverMaxLength, nameMajor, 50);

            if (!Queryable.Any(_dataContex.Faculties, f => f.Id == idFaculty))
                return ConstantMessages.CanNotIdentifyItem;

            return Queryable.Any(_dataContex.Majors, m => m.Name.ToLower() == nameMajor.ToLower())
                       ? string.Format(ConstantMessages.ItemIsExisted, nameMajor)
                       : string.Empty;
        }

        /// <summary>
        /// This function adds new a major in a facutly
        /// </summary>
        /// <param name="nameMajor"> Name of new major</param>
        /// <param name="idFaculty"> Name of facutly</param>
        public void AddMajor(string nameMajor, int idFaculty)
        {
            _dataContex.Majors.AddObject(new Major {Name = nameMajor, IdFaculty = idFaculty});

            _dataContex.SaveChanges();
        }

        /// <summary>
        /// This fuction check validate of edit a major function 
        ///     Is major exsist
        ///     Is new name of major same as orther major
        /// </summary>
        /// <param name="idMajor"></param>
        /// <param name="nameMajor"></param>
        /// <returns></returns>
        public string EditMajorValidator(int idMajor, string nameMajor)
        {
            if (string.IsNullOrEmpty(nameMajor))
                return string.Format(ConstantMessages.RequireFieldIsBlank, "tên ngành");

            if (nameMajor.Length >= 50)
                return string.Format(ConstantMessages.FieldDataOverMaxLength, nameMajor, 50);

            if (!Queryable.Any(_dataContex.Majors, m => m.Id == idMajor))
                return string.Format(ConstantMessages.CanNotIdentifyItem);

            return Queryable.Any(_dataContex.Majors, m => m.Name.ToLower() == nameMajor.ToLower() && m.Id != idMajor)
                       ? string.Format(ConstantMessages.ItemIsExisted, nameMajor)
                       : string.Empty;
        }

        /// <summary>
        /// This fuction edits a major
        /// </summary>
        /// <param name="id"></param>
        /// <param name="nameMajor"></param>
        public void EditMajor(int id, string nameMajor)
        {
            Major idMajor = Queryable.FirstOrDefault(Queryable.Where(_dataContex.Majors, f => f.Id == id));

            if (idMajor == null) return;

            idMajor.Name = nameMajor;

            _dataContex.SaveChanges();
        }

        /// <summary>
        /// This fuction checks validate of delete a major fuction
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>       
        public string DeleteMajorValidator(int[] ids)
        {
            System.Linq.IQueryable<Major> deleteMajors = Queryable.Where(_dataContex.Majors,
                                                                         c => Enumerable.Contains(ids, c.Id));

            if (_dataContex == null || ids.Length <= 0 || Enumerable.ToList(deleteMajors).Count != ids.Length)
                return string.Format(ConstantMessages.CanNotIdentifyItem);

            System.Linq.IQueryable<int> capacitiesForiegnKey = Queryable.Select(_dataContex.Capacities, c => c.IdMajor);
            List<Major> impactedMajors =
                Enumerable.ToList(Queryable.Where(deleteMajors, f => Queryable.Contains(capacitiesForiegnKey, f.Id)));
            string listNameMajor = null;

            listNameMajor = Enumerable.Aggregate(impactedMajors, listNameMajor,
                                                 (current, impactedMajor) => current + impactedMajor.Name + ", ");

            return listNameMajor != null
                       ? string.Format(ConstantMessages.CannotDeleteItemInUse, listNameMajor.TrimEnd(',', ' '),
                                       " một số giới hạn số chỉ")
                       : string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ids"></param>
        public void DeleteMajor(int[] ids)
        {
            System.Linq.IQueryable<Major> deleteMajors = Queryable.Where(_dataContex.Majors,
                                                                         c => Enumerable.Contains(ids, c.Id));

            foreach (Major deleteMajor in deleteMajors)
                _dataContex.DeleteObject(deleteMajor);

            _dataContex.SaveChanges();
        }

        #endregion

        #region -- Course --

        public List<Course> GetListCourse()
        {
            return Enumerable.ToList(_dataContex.Courses);
        }

        /// <summary>
        /// This function check validate of add a new course function
        ///     Is name exist?
        /// </summary>
        /// <param name="nameCourse"> Name of course </param>
        /// <returns></returns>
        public string AddCourseValidator(string nameCourse)
        {
            if (string.IsNullOrEmpty(nameCourse))
                return string.Format(ConstantMessages.RequireFieldIsBlank, "tên kỳ");

            if (nameCourse.Length >= 50)
                return string.Format(ConstantMessages.FieldDataOverMaxLength, nameCourse, 50);

            return Queryable.Any(_dataContex.Courses, c => c.Name.ToLower() == nameCourse.ToLower())
                       ? string.Format(ConstantMessages.ItemIsExisted, nameCourse)
                       : string.Empty;
        }

        /// <summary>
        /// This function adds new course
        /// </summary>
        /// <param name="nameCourse"></param>
        public void AddCourse(string nameCourse)
        {
            _dataContex.Courses.AddObject(new Course {Name = nameCourse});

            _dataContex.SaveChanges();
        }

        /// <summary>
        /// This function checks validate of edit a course function
        /// </summary>
        /// <param name="idCourse">Id of course which is edited</param>
        /// <param name="nameCourse"> New name course </param>
        /// <returns></returns>
        public string EditCourseValidator(int idCourse, string nameCourse)
        {
            if (string.IsNullOrEmpty(nameCourse))
                return string.Format(ConstantMessages.RequireFieldIsBlank, "tên kỳ");

            if (nameCourse.Length >= 50)
                return string.Format(ConstantMessages.FieldDataOverMaxLength, nameCourse, 50);

            if (!Queryable.Any(_dataContex.Courses, f => f.Id == idCourse))
                return ConstantMessages.CanNotIdentifyItem;

            return Queryable.Any(_dataContex.Courses, c => c.Name.ToLower() == nameCourse.ToLower() && c.Id != idCourse)
                       ? string.Format(ConstantMessages.ItemIsExisted, nameCourse)
                       : string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="nameCourse"></param>
        public void EditCourse(int id, string nameCourse)
        {
            Course idCourse = Queryable.FirstOrDefault(Queryable.Where(_dataContex.Courses, c => c.Id == id));

            if (idCourse == null) return;

            idCourse.Name = nameCourse;

            _dataContex.SaveChanges();
        }

        /// <summary>
        /// This function checks validate of delete a course function
        /// </summary>
        /// <param name="ids"> List ids of couses what is deleted </param>
        /// <returns></returns>
        public string DeleteCourseValidator(int[] ids)
        {
            //System.Linq.IQueryable<Course> deleteCourses = Queryable.Where(_dataContex.Courses,
            //                                                               c => Enumerable.Contains(ids, c.Id));

            //if (_dataContex == null || ids.Length <= 0 || Enumerable.ToList(deleteCourses).Count != ids.Length)
            //    return string.Format(ConstantMessages.CanNotIdentifyItem);

            //var capacitiesForiegnKey = _dataContex.Capacities.Select(c => c.IdCourse);
            //var impactedCourses = deleteCourses.Where(f => capacitiesForiegnKey.Contains(f.Id)).ToList();
            string listNameCourse = null;

            //listNameCourse = impactedCourses.Aggregate(listNameCourse,
            //                                           (current, impactedCourse) => current + impactedCourse.Name + ", ");

            return listNameCourse != null
                       ? string.Format(ConstantMessages.CannotDeleteItemInUse, listNameCourse.TrimEnd(',', ' '),
                                       " một số giới hạn số chỉ")
                       : string.Empty;
        }

        public void DeleteCourse(int[] ids)
        {
            System.Linq.IQueryable<Course> deleteCourses = Queryable.Where(_dataContex.Courses,
                                                                           c => Enumerable.Contains(ids, c.Id));

            foreach (Course deleteCourse in deleteCourses)
                _dataContex.DeleteObject(deleteCourse);

            _dataContex.SaveChanges();
        }

        #endregion

        #region -- Capacity --

        public List<Capacity> GetListCapacityByMajor(int idMajor)
        {
            return (idMajor > 0)
                       ? Enumerable.ToList(Queryable.Where(_dataContex.Capacities, c => c.IdMajor == idMajor))
                       : Enumerable.ToList(_dataContex.Capacities);
        }

        public void AddCapacityByMajor(int idMajor)
        {
            System.Linq.IQueryable<int> listCourses = Queryable.Select(_dataContex.Courses, c => c.Id);

            if (!Queryable.Any(_dataContex.Majors, c => c.Id == idMajor)) return;

            foreach (int idCourse in listCourses)
                _dataContex.Capacities.AddObject(new Capacity
                                                     {
                                                         IdMajor = idMajor,
                                                         IdCourse = idCourse,
                                                         MaxCredit = PropertiesConstants.MaxCredit,
                                                         MinCredit = PropertiesConstants.MinCredit
                                                     });
            _dataContex.SaveChanges();
        }

        public void AddCapacityByCourse(int idCourse)
        {
            System.Linq.IQueryable<int> listMajors = Queryable.Select(_dataContex.Majors, m => m.Id);

            if (!Queryable.Any(_dataContex.Courses, c => c.Id == idCourse)) return;

            foreach (int idMajor in listMajors)
                _dataContex.Capacities.AddObject(new Capacity
                                                     {
                                                         IdMajor = idMajor,
                                                         IdCourse = idCourse,
                                                         MaxCredit = PropertiesConstants.MaxCredit,
                                                         MinCredit = PropertiesConstants.MinCredit
                                                     });
            _dataContex.SaveChanges();
        }

        public string EditCapacityValidator(int[] ids)
        {
            //if (ids.Length == 4)
            //{
            //    int idMajor = ids[0];
            //    int idCourse = ids[1];
            //    int maxCredit = ids[2];
            //    int minCredit = ids[3];
            //    var capacity =
            //        _dataContex.Capacities.Where(c => c.IdMajor == idMajor && c.IdCourse == idCourse).FirstOrDefault();

            //    if (maxCredit > 100 || minCredit > 100)
            //        return string.Format(ConstantMessages.FieldDataOverMaxLength, "Giá trị", 100);

            //    if (maxCredit < minCredit) return string.Format(ConstantMessages.CapacityInvalideData);

            //    if (capacity == null)
            //        return string.Format(ConstantMessages.CanNotIdentifyItem);

            //    return _dataContex.Capacities.Any(
            //        c =>
            //        c.IdMajor == idMajor && c.IdCourse == idCourse && c.MaxCredit == maxCredit &&
            //        c.MinCredit == minCredit)
            //               ? string.Format(ConstantMessages.ItemIsExisted, "giới hạn tín chỉ")
            //               : string.Empty;
            //}
            return string.Format(ConstantMessages.CanNotIdentifyItem);
        }

        public void EditCapacity(int[] ids)
        {
            //int idMajor = ids[0];
            //int idCourse = ids[1];
            //int maxCredit = ids[2];
            //int minCredit = ids[3];
            //var capacity =
            //    _dataContex.Capacities.Where(c => c.IdMajor == idMajor && c.IdCourse == idCourse).FirstOrDefault();

            //if (capacity == null) return;

            //capacity.MaxCredit = maxCredit;
            //capacity.MinCredit = minCredit;

            //_dataContex.SaveChanges();
        }

        public void DeleteCapacityByMajor(int[] listMajorsIds)
        {
            //System.Linq.IQueryable<int> listCourse = Queryable.Select(_dataContex.Courses, c => c.Id);

            //if (Queryable.Count(listCourse) <= 0) return;

            //foreach (var deleteCapacity in
            //    listMajorsIds.SelectMany(idMajor => listCourse, (idMajor, IdCourse) => _dataContex.Capacities.Where(
            //        c => c.IdMajor == idMajor && c.IdCourse == IdCourse).FirstOrDefault()))
            //    _dataContex.DeleteObject(deleteCapacity);

            //_dataContex.SaveChanges();
        }

        public void DeleteCapacityByCourse(int[] listIdCourses)
        {
            //System.Linq.IQueryable<int> listMajor = Queryable.Select(_dataContex.Majors, m => m.Id);

            //if (Queryable.Count(listMajor) <= 0) return;

            //foreach (var deleteCapacity in from idMajor in listMajor
            //                               from idCourse in listIdCourses
            //                               select
            //                                   _dataContex.Capacities.Where(
            //                                       c => c.IdMajor == idMajor && c.IdCourse == idCourse).
            //                                   FirstOrDefault())
            //    _dataContex.DeleteObject(deleteCapacity);

            //_dataContex.SaveChanges();
        }

        #endregion
    }
}